package app.model.flare.vos
{
	import flash.events.EventDispatcher;
	
	import mx.collections.ArrayCollection;
	
	public class StateVO extends EventDispatcher implements IEncodeable, IDecodeable
	{
		public static const PACKAGE_DELIMITER:String = ".";
		public static const CASE_DELIMITER:String = " ";
		public static const CAPS_DELIMITER:String = "_";
		public static const STATE_PREFIX:String = "state/";
		public static const ENTERING_PREFIX:String = "entering/";
		public static const EXITING_PREFIX:String = "exiting/";
		public static const CHANGED_PREFIX:String = "changed/";
		public static const ROOT:String = "root";
		
		[Bindable]
		public var targets:ArrayCollection;
		public var order:int;
		[Bindable]
		public var initial:Boolean;
		[Bindable]
		public var entering:Boolean;
		[Bindable]
		public var changed:Boolean;
		[Bindable]
		public var exiting:Boolean;
		[Bindable]
		public var label:String;
		
		private var _splitPath:Array;		
		
		public function StateVO( o:Object=null)
		{
			if( o )encode( o );
		}
		
		public function addAction( action:ActionVO ):void{
			if(!targets){
				targets = new ArrayCollection([action])
			}else{
				targets.addItem( action );
			}
			
		}
		
		
		
		public function removeAction( actionName:String ):void{
			var n:int,
				vo:ActionVO;
			while( n < targets.length ){
				vo = targets[n];
				if(vo.name == actionName){
					targets.removeItemAt(n);
				};
				n++;
			}
			
		}
		
		public function contains( actionName:String ):Boolean{
				var n:int,
				vo:ActionVO;
			if(!targets)return false;
			while( n < targets.length ){
				vo = targets[n];
				if(vo.name == actionName)return true;
				n++;
			}
			return false;
		}
		
		private function setLabel():void{
			label = name;
		}
		
		public function containsTarget( stateName:String ):Boolean{
				var n:int,
				vo:ActionVO;
			if(!targets)return false;
			while( n < targets.length ){
				vo = targets[n];
				if(vo.target.name == stateName)return true;
				n++;
			}
			return false;
		}
		
		public function inseminate(states:Array):void{
			var action:ActionVO;
			for each (action in targets) {
				action.inseminate(states)
			}
		}
		
		public function encode(o:Object):void{
			fullPath = o.fullPath;
			order = o.order;
			entering = o.entering;
			exiting = o.exiting;
			changed = o.changed;
			initial = o.initial;
			targets = encodeActions( o.targets );
			setLabel();
		}
		
		public function toXML():XML{
			var xml:XML = new XML(<state name={STATE_PREFIX+name}/>);
			if(changed)xml.@changed = CHANGED_PREFIX + slug;
			if(entering)xml.@entering = ENTERING_PREFIX + slug;
			if(exiting)xml.@exiting = EXITING_PREFIX + slug;
			
			for each(var action:ActionVO in targets){
				xml.appendChild( action.toXML() );
			}
			
			return xml;
			
		}
		
		
		public function decode():Object{
			return {	fullPath:this.fullPath, 
						entering:this.entering,
						exiting:this.exiting,
						changed:this.changed,
						initial:this.initial,
						targets:decodeTargets()
						};
		}
		
		private function decodeTargets():Array{
			var a:Array = [];
			for each (var vo:ActionVO in targets ){
				a.push(vo.decode())
			}
			return a;
		}
		
		private function encodeActions( list:Array ):ArrayCollection{
			var n:int,
				a:ArrayCollection,
				o:Object,
				action:ActionVO;
			a = new ArrayCollection();
			while( n < list.length ){
				o = list[n];
				action = new ActionVO ();
				action.encode( o )
				a.addItem( action );
				n++;
			}
			return a;
		}
		
		
		public function get fullPath():String{
			return _splitPath.join(PACKAGE_DELIMITER);
		}
		
		public function set fullPath(v:String):void{
			_splitPath = v.split(PACKAGE_DELIMITER);
			setLabel();
		}
		
		[Bindable]
		public function get name():String{
			return _splitPath[_splitPath.length-1];
		}
		
		public function set name(v:String):void{
			_splitPath[_splitPath.length-1] = v;
			setLabel();
		}
		
		[Bindable]
		public function get pkg():String{
			return _splitPath.slice(1, _splitPath.length-1).join(PACKAGE_DELIMITER);
		}
		
		public function set pkg(v:String):void{
			var p:String = ROOT + PACKAGE_DELIMITER + v + PACKAGE_DELIMITER + name;
			_splitPath = p.split(PACKAGE_DELIMITER)
		}
		

		
		public function get slug():String{
			var split:Array = name.toLowerCase().split(CASE_DELIMITER),
				n:int = 0,
				s:String,
				p:String;
			while( n < split.length ){
				p = String(split[n])
				s = p.charAt().toUpperCase();
				split[n] = s + p.slice(1);
				n++;
			}
			
			return split.join("");
		} 
		
		public function get capsSlug():String{
			var split:Array = name.toUpperCase().split(CASE_DELIMITER);			
			return STATE_PREFIX.toUpperCase() + CAPS_DELIMITER +split.join(CAPS_DELIMITER);
		} 
		
		public function get pkgArray():Array{
			return _splitPath.slice(0, _splitPath.length-1);
		}
		

	}
} 